package com.ghy.seckill.schedule;

import cn.hutool.core.bean.BeanUtil;



import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ghy.seckill.entity.PmsSkuInfo;
import com.ghy.seckill.entity.SmsSeckillSession;
import com.ghy.seckill.entity.SmsSeckillSkuRelation;

import com.ghy.seckill.service.PmsSkuInfoService;
import com.ghy.seckill.service.SmsSeckillSessionService;
import com.ghy.seckill.service.SmsSeckillSkuRelationService;
import com.ghy.seckill.util.R;
import com.ghy.seckill.vo.OrderVo;
import com.ghy.seckill.vo.RedisSkuVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Service
@Slf4j
public class ScheduleTaskImpl implements ScheduleTask {
    @Autowired
    private SmsSeckillSessionService smsSeckillSessionService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SmsSeckillSkuRelationService smsSeckillSkuRelationService;
    @Autowired
    private PmsSkuInfoService pmsSkuInfoService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedissonClient redissonClient;
    private final String SESSION__CACHE_PREFIX = "seckill:sessions:";
    private final String SECKILL_CHARE_PREFIX = "seckill:skus";

    private final String SKU_STOCK_SEMAPHORE = "seckill:stock:";    //+商品随机码


    /**
     * 缓存活动和关联的商品信息
     */
    @Override
    public void uploadSeckillProduct() {
        //查出两天内所有活动
        List<SmsSeckillSession> sessions = smsSeckillSessionService.GamePrestrain(getStartTime(), getEndTime());
        for (SmsSeckillSession SmsSeckillSession : sessions) {
            //查出活动关联的商品，
            List<SmsSeckillSkuRelation> gameSku = smsSeckillSkuRelationService.getGameSku(SmsSeckillSession.getId());
            SmsSeckillSession.setRelationSkus(gameSku);
            System.out.println(SmsSeckillSession);

            //缓存活动信息
            //获取当前活动的开始和结束时间的时间戳
            long startTime = SmsSeckillSession.getStartTime().getTime();
            long endTime = SmsSeckillSession.getEndTime().getTime();

            //存入到Redis中的key
            String key = SESSION__CACHE_PREFIX + startTime + "_" + endTime;

            //判断Redis中是否有该信息，如果没有才进行添加
            Boolean hasKey = redisTemplate.hasKey(key);
            if (!hasKey){
                for (SmsSeckillSkuRelation relationSkus : SmsSeckillSession.getRelationSkus()) {
                    redisTemplate.opsForList().leftPush(key,relationSkus.getPromotionSessionId()+"-"+ relationSkus.getSkuId());
                }
            }

            //缓存活动商品信息
            BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(SECKILL_CHARE_PREFIX);
            RedisSkuVo redisSkuVo=new RedisSkuVo();
            List<SmsSeckillSkuRelation> relationSkus = SmsSeckillSession.getRelationSkus();
            for (SmsSeckillSkuRelation skus : relationSkus) {
                String redisKey= skus.getPromotionSessionId().toString() + "-" + skus.getSkuId().toString();
                if (!operations.hasKey(redisKey)){
                    PmsSkuInfo skuInfos = pmsSkuInfoService.skuById(skus.getSkuId());
                    //sku商品的秒杀信息
                    redisSkuVo.setSkuInfo(skuInfos);

                    BeanUtil.copyProperties(skus,redisSkuVo);

                    //3、设置当前商品的秒杀时间信息
                    redisSkuVo.setStartTime(SmsSeckillSession.getStartTime().getTime());
                    redisSkuVo.setEndTime(SmsSeckillSession.getEndTime().getTime());
                    //4、设置商品的随机码
                    String token = UUID.randomUUID().toString().replace("-", "");
                    redisSkuVo.setRandomCode(token);

                    operations.put(redisSkuVo.getPromotionSessionId().toString() + "-" + redisSkuVo.getSkuId().toString(),redisSkuVo);


                    //  Redisson限流
                    RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + token);
                    // 使用商品可以秒杀总量作为限制
                    semaphore.trySetPermits(redisSkuVo.getSeckillCount());
                }


            }


        }

    }

    /**
     * 秒杀开始
     * @param promotionSessionId
     * @param killId
     * @param key
     * @param num
     * @return
     */
    @Override
    public R seckill(String promotionSessionId, String killId, String key, Integer num) {

        log.info("秒杀开始了{}");
//       判断当前用户是否登录，模拟已经登录
        boolean user=true;
        if (!user){
            return new R(-888,"未登录",null);
        }
        //获取当前秒杀商品信息
        redisTemplate.opsForList().getOperations();
        Object redisSku = redisTemplate.opsForHash().get(SECKILL_CHARE_PREFIX,promotionSessionId + "-" + killId);
        System.out.println(redisSku);
        if (redisSku==null){
            return new R(-22,"商品未上架",null);
        }
        //判断当前活动是否未开始，或者已经结束
        long newDate = System.currentTimeMillis();
        RedisSkuVo redisSkuVo=new RedisSkuVo();
        BeanUtil.copyProperties(redisSku,redisSkuVo);
        Long startTime = redisSkuVo.getStartTime();
        Long endTime = redisSkuVo.getEndTime();
        if (newDate<startTime || newDate>endTime){
            return new R(-33,"不在活动时间",null);
        }
        //校验商品随机码和商品id
//        if (!redisSkuVo.getSkuId().equals(killId) || !redisSkuVo.getRandomCode().equals(key)){
//            return new R(-44,"商品不存在，非法请求",null);
//        }
        Integer seckillLimit = redisSkuVo.getSeckillLimit();

        Object o = redisTemplate.opsForValue().get(SKU_STOCK_SEMAPHORE + redisSkuVo.getRandomCode());
        System.out.println("当前库存量"+o);
        Integer count = Integer.valueOf((Integer) o);
        //判断秒杀总量是否大于0，判断购物数量是否超上限，判断购买数量是否超过秒杀总量
        if (count<=0 || num > seckillLimit || count < num ){
            return new R(-44,"购买已超上限，商品总量不足",null);
        }
        //验证当前用户是否已经参与过秒杀抢购
//        String userKey = "userID-" + promotionSessionId + "-" + killId;
//        //设置自动过期(活动结束时间-当前时间)
//        Long ttl = endTime - newDate;
//        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(userKey, num.toString(), ttl, TimeUnit.MILLISECONDS);
//        if (!aBoolean){
//            return new R(-55,"不能重复参与本活动",null);
//        }
        //秒杀成功
        try {
             //减redis商品秒杀数量
            RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + redisSkuVo.getRandomCode());
            semaphore.tryAcquire(num,100,TimeUnit.MICROSECONDS);
            //发送mq 创建订单，返回订单号
            OrderVo orderVo=new OrderVo();
            String timeId = IdWorker.getTimeId();
            orderVo.setOrderSn(timeId);
            orderVo.setNum(num);
            orderVo.setPromotionSessionId(redisSkuVo.getPromotionSessionId());
            orderVo.setSkuId(redisSkuVo.getSkuId());
            orderVo.setSeckillPrice(redisSkuVo.getSeckillPrice());
            orderVo.setSkuPic(redisSkuVo.getSkuInfo().getSkuDefaultImg());
            rabbitTemplate.convertAndSend("order-event-exchange","order.seckill.order",orderVo);

            return new R(888,"秒杀成功",orderVo.getOrderSn());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new R();

    }

    /**
     * 获取当前时间段可以参加秒杀的商品信息
     * @return
     */
    @Override
    public List<RedisSkuVo> getCurrentSeckillSkus() {
        //1、确定当前属于哪个秒杀场次
        long currentTime = System.currentTimeMillis();
       //从Redis中查询到所有key以seckill:sessions开头的所有数据
        Set<String> keys = redisTemplate.keys(SESSION__CACHE_PREFIX + "*");
        for (String key : keys) {
            String replace = key.replace(SESSION__CACHE_PREFIX, "");
            String[] s = replace.split("_");
            //获取存入Redis商品的开始时间
            long startTime = Long.parseLong(s[0]);
            //获取存入Redis商品的结束时间
            long endTime = Long.parseLong(s[1]);
            //判断是否是当前秒杀场次
            if (currentTime >= startTime && currentTime <= endTime) {
                List range = redisTemplate.opsForList().range(key, -100, 100);
                BoundHashOperations<String, String, String> hasOps = redisTemplate.boundHashOps(SECKILL_CHARE_PREFIX);
                List list = hasOps.multiGet(range);
                System.out.println(list);
                if (list!=null && list.size()>=0 ){
                    return list;
                }
                break;
            }

        }

        return null;
    }


    public String getStartTime(){
        LocalDate now = LocalDate.now();
        LocalTime min = LocalTime.MIN;
        LocalDateTime dateTime = LocalDateTime.of(now, min);
        String startTime = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));


        return startTime;
    }

    public String getEndTime(){
        LocalDate localDate = LocalDate.now();
        LocalTime max= LocalTime.MAX;
        LocalDate plusDays = localDate.plusDays(1);
        LocalDateTime dateTimeMax = LocalDateTime.of(plusDays, max);
        String endTime = dateTimeMax.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        return endTime;
    }

}
